package com.keqiang.chart.impl.axis.impl.bar.horizontal

import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.text.TextPaint
import com.keqiang.chart.animation.Animator
import com.keqiang.chart.impl.axis.render.BaseDataRender
import com.keqiang.chart.utils.ObjectPool
import com.keqiang.utils.PaintUtils.getCenterBaseline

/**
 * 绘制柱状图柱形图
 *
 * @author Created by wanggaowan on 2022/7/26 11:33
 */
open class BarChartHorizontalDataRender(chart: BarChartHorizontal) : BaseDataRender<BarChartHorizontal>(chart) {

    override fun onDraw(canvas: Canvas, start: Float, top: Float, end: Float, bottom: Float,
                        gridWidth: Float, gridHeight: Float, animator: Animator?) {
        val barData = chart.data ?: return

        canvas.save()
        canvas.clipRect(start - chart.xAxis.startPadding,
            top - chart.yAxis.endPadding,
            end + chart.xAxis.endPadding,
            bottom + chart.yAxis.startPadding)

        barData.groups?.let {
            drawBar(canvas, it, start, end, bottom, gridHeight, animator)
            drawValueText(canvas, it, end)
        }

        canvas.restore()

        if ((animator?.getProgress() ?: 1f) == 1f) {
            chart.touchHandler?.touchData?.let {
                chart.highLightRender?.onDraw(canvas, start, top, end, bottom, it)
            }
        }
    }

    /**
     * 绘制柱状图
     */
    protected open fun drawBar(canvas: Canvas, dataList: List<BarGroup>, start: Float, end: Float, bottom: Float, gridHeight: Float, animator: Animator?) {
        val xAxis = chart.xAxis
        var tempBottom = bottom
        val range = end - start
        val maxValue = xAxis.max - xAxis.min
        val paint = ObjectPool.obtainPaint<Paint>()
        paint.style = Paint.Style.FILL

        for (data in dataList) {
            if (data.values.isEmpty()) {
                continue
            }

            var totalPercent = 0f
            data.values.forEach { entity ->
                totalPercent += entity.widthPercent
            }

            val height = gridHeight - data.barOffset * (data.values.size - 1)
            var drawBottom = if (totalPercent >= 1 || data.gravity == BarGroup.GRAVITY_BOTTOM) {
                tempBottom
            } else if (data.gravity == BarGroup.GRAVITY_TOP) {
                tempBottom - height * (1 - totalPercent)
            } else {
                tempBottom - height * (1 - totalPercent) / 2f
            }

            data.values.forEach { entity ->
                val barHeight = entity.widthPercent * height
                val alpha = Color.alpha(entity.bgColor)
                if (alpha > 0) {
                    entity.drawRectF.set(start, drawBottom - barHeight, end, drawBottom)
                    paint.color = entity.bgColor
                    paint.shader = null
                    canvas.drawRect(entity.drawRectF, paint)
                }

                val barWidth =
                    (entity.value - xAxis.min) / maxValue * range * (animator?.getProgress() ?: 1f)
                entity.drawRectF.set(start, drawBottom - barHeight, start + barWidth, drawBottom)
                paint.color = entity.color
                paint.shader =
                    entity.shaderFactory?.invoke(start, entity.drawRectF.top, end, entity.drawRectF.bottom)
                canvas.drawRect(entity.drawRectF, paint)
                drawBottom -= barHeight + data.barOffset
            }

            tempBottom -= gridHeight
        }

        ObjectPool.recyclePaint(paint)
    }

    /**
     * 绘制柱状图文本
     */
    protected open fun drawValueText(canvas: Canvas, dataList: List<BarGroup>, end: Float) {
        val textPaint = ObjectPool.obtainPaint<TextPaint>(true)
        textPaint.textAlign = Paint.Align.LEFT
        for (data in dataList) {
            if (data.values.isEmpty()) {
                continue
            }

            data.values.forEach { entity ->
                if (entity.drawLabel) {
                    val text = entity.label
                    if (!text.isNullOrEmpty()) {
                        textPaint.color = entity.labelColor
                        textPaint.textSize = entity.labelTextSize


                        val x = if (entity.labelFixTop) {
                            end + entity.labelOffset
                        } else {
                            var x2 = entity.drawRectF.right + entity.labelOffset
                            val textWidth = textPaint.measureText(text)
                            if (x2 + textWidth > end + chart.xAxis.endPadding) {
                                x2 = entity.drawRectF.right - textWidth - entity.labelOffset
                            }
                            x2
                        }

                        val y =
                            entity.drawRectF.top + entity.drawRectF.height() / 2f + textPaint.getCenterBaseline(includePadding = false)
                        canvas.drawText(text, x, y, textPaint)
                    }
                }
            }
        }

        ObjectPool.recyclePaint(textPaint)
    }
}